// g++ -shared -fPIC -fvisibility=default -I../include -I../3rd/lua-5.4.7/src -I../3rd -L../libs -Wl,-rpath=../libs -llua -lspdlog packet_base.cc lua_packet.cc log.cc -o libpacket.so

#include "lua.hpp"

#include <stdio.h>

#include <iostream>

#include "packet_base.h"
// #include "log.h"


#if defined(_WIN32) || defined(_WIN64)
    #define _DLLExport _declspec(dllexport)
#else
    #define _DLLExport __attribute__((visibility("default")))
#endif


static int CreatePacket(lua_State* L){
    // LOG_DEBUG("CreatePacket");
    printf("CreatePacket");

    PacketBase** p = (PacketBase**)lua_newuserdata(L, sizeof(PacketBase));
    *p = new PacketBase();
    
    luaL_getmetatable(L, "packetbase");
    lua_setmetatable(L, -2);

    return 1;
}

static int LuaDeletePacket(lua_State* L){
    // LOG_DEBUG("LuaDeletePacket");
    printf("LuaDeletePacket");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");
    
    if (p) {
        // LOG_DEBUG("lua delete packet");
        printf("lua delete packet");
        delete *p;
    }

    return 1;
}

static int Copy(lua_State* L){
    printf("Copy");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    void* msg = lua_touserdata(L, 2);
    luaL_argcheck(L, msg != NULL, 1, "invalid msg data");

    int len = (int)luaL_checkinteger(L, 3);

    (*p)->Copy(msg, len);

    return 1;
}

static int GetBuffer(lua_State* L){
    printf("GetBuffer");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int size = (*p)->GetBufferSize();
    char* buff = (*p)->GetBuffer();

    lua_pushlightuserdata(L, buff);
    lua_pushinteger(L, size);
    
    return 2;
}

static int WriteBegin(lua_State* L){
    printf("WriteBegin");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    short cmd = luaL_checkinteger(L, 2);
    (*p)->Begin(cmd);

    return 1;
}

static int WriteEnd(lua_State* L){
    printf("WriteEnd");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    (*p)->End();

    return 1;
}

static int WriteInt16(lua_State* L){
    printf("WriteInt16");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    short val = luaL_checkinteger(L, 2);
    (*p)->WriteInt16(val);

    return 1;
}

static int ReadInt16(lua_State* L){
    printf("ReadInt16");

    PacketBase** p = (PacketBase**)luaL_checkudata(L, 1, "packetbase");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int v = (*p)->ReadInt16();
    lua_pushinteger(L, v);

    return 1;
}

static const luaL_Reg RegisterInfo[] = {
    {"__gc", LuaDeletePacket},
    
    {"CreatePacket", CreatePacket},
    {"Copy", Copy},
    {"GetBuffer", GetBuffer},
    {"WriteBegin", WriteBegin},
    {"WriteEnd", WriteEnd},
    {"WriteInt16", WriteInt16},
    {"ReadInt16", ReadInt16},

    {NULL, NULL}
};

extern "C" _DLLExport int luaopen_libpacketbase(lua_State *L)
{
    luaL_newmetatable(L, "packetbase");
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");

	luaL_setfuncs(L, RegisterInfo, 0);

    return 1;
}